/**
 *	@file	safari_sv.c
 *	@brief	サファリゾーン　セーブデータ
 *	@author	Miyuki Iwasawa
 *	@date	08.03.13
 */

#include "common.h"
#include "system/pm_str.h"
#include "safari/safari_sys.h"
#include "savedata/savedata.h"
#include "savedata/playtime_local.h"
#include "safari_sv_local.h"
#include "system/pm_rtc.h" //GF_RTC_GetDateTimeBySecond
#include "gflib/strbuf_family.h" //STRBUF_GetStringCode


//////////////////////////////////////////////////////////////////////
///プロトタイプ
static void safarisv_clear(SAFARI_SAVE* sv);
static void layout_clear(SAFARI_LAYOUT* layout);
static void block_clear(SAFARI_BLOCK* block,u8 block_id);
static void obj_clear(SAFARI_OBJ* obj);
static void manager_clear(SAFARI_MANAGER* dat);
static BOOL mapchip_IsAlreadyLvUp(u8 map_id,u8* up_list,u8 num);


//データ
static const u8 DATA_SafariBlockTbl[][6] = {
 {	//00
	SAFARI_MAP_PLANE,SAFARI_MAP_FOREST_W,SAFARI_MAP_FLOWER,
	SAFARI_MAP_DAMP,SAFARI_MAP_ROCKY,SAFARI_MAP_FOREST,
 },
 {	//01
	SAFARI_MAP_FLOWER,SAFARI_MAP_BOGGY,SAFARI_MAP_DAMP,
	SAFARI_MAP_FOREST,SAFARI_MAP_ROCKY,SAFARI_MAP_FOREST_W,
 },
 {	//02
	SAFARI_MAP_DAMP,SAFARI_MAP_BARREN,SAFARI_MAP_FOREST,
	SAFARI_MAP_FOREST_W,SAFARI_MAP_ROCKY,SAFARI_MAP_BOGGY,
 },
 {	//03
	SAFARI_MAP_FOREST,SAFARI_MAP_MOUNTAIN,SAFARI_MAP_FOREST_W,
	SAFARI_MAP_BOGGY,SAFARI_MAP_ROCKY,SAFARI_MAP_BARREN,
 },
 {	//04
	SAFARI_MAP_FOREST_W,SAFARI_MAP_SAVANNA,SAFARI_MAP_BOGGY,
	SAFARI_MAP_BARREN,SAFARI_MAP_ROCKY,SAFARI_MAP_MOUNTAIN,
 },
 {	//05
	SAFARI_MAP_BOGGY,SAFARI_MAP_PLANE,SAFARI_MAP_BARREN,
	SAFARI_MAP_MOUNTAIN,SAFARI_MAP_ROCKY,SAFARI_MAP_SAVANNA,
 },
 {	//06
	SAFARI_MAP_BARREN,SAFARI_MAP_FLOWER,SAFARI_MAP_MOUNTAIN,
	SAFARI_MAP_SAVANNA,SAFARI_MAP_ROCKY,SAFARI_MAP_PLANE,
 },
 {	//07
	SAFARI_MAP_MOUNTAIN,SAFARI_MAP_DAMP,SAFARI_MAP_SAVANNA,
	SAFARI_MAP_PLANE,SAFARI_MAP_ROCKY,SAFARI_MAP_FLOWER,
 },
 {	//08
	SAFARI_MAP_SAVANNA,SAFARI_MAP_FOREST,SAFARI_MAP_PLANE,
	SAFARI_MAP_FLOWER,SAFARI_MAP_ROCKY,SAFARI_MAP_DAMP,
 },
 {	//09
	SAFARI_MAP_PLANE,SAFARI_MAP_SAVANNA,SAFARI_MAP_DAMP,
	SAFARI_MAP_FOREST_W,SAFARI_MAP_ROCKY,SAFARI_MAP_BARREN,
 },
};
//////////////////////////////////////////////////////////////////////
///グローバル

/**
 *	@brief	サファリセーブデータサイズ取得
 */
int SafariSv_GetWorkSize(void)
{
	return sizeof(SAFARI_SAVE);
}

/**
 *	@brief	サファリデータブロックへのポインタを取得
 */
SAFARI_SAVE* SaveData_GetSafariSave(SAVEDATA* sv)
{
	return SaveData_Get(sv,GMDATA_ID_SAFARI_SAVE);
}

/**
 *	@brief	サファリデータ　初期データ
 */
void SafariSv_Init(SAFARI_SAVE* sv)
{
	int i;

	for(i = 0;i < SAFARI_LAYOUT_MAX;i++){
		MI_CpuClear8(&sv->layout[i],sizeof(SAFARI_LAYOUT));
	}

	manager_clear(&sv->manager);
}

/**
 *	@brief	サファリのレイアウトデータ初期化
 *
 *	トレーナーIDに応じて、初期パターンが決まる
 */
void SafariSv_MyLayoutInit(SAFARI_SAVE* sv,u32 tr_id)
{
	int i,pat;
	SAFARI_LAYOUT* pl = &sv->layout[SAFARI_LAYOUT_MINE];

	pat = tr_id%10;
	for(i = 0;i < SAFARI_BLOCK_MAX;i++){
		block_clear(&pl->block[i],DATA_SafariBlockTbl[pat][i]);
	}
	MI_CpuClear8(pl->map_level,sizeof(u8)*SAFARI_MAP_MAX);
}

/**
 *	@brief	サファリゲーム中に参照するレイアウトIDを保存
 */
void SafariSv_SetGameLayoutID(SAFARI_SAVE* sv,SAFARI_LAYOUT_ID id)
{
	if(id >= SAFARI_LAYOUT_MAX){
		GF_ASSERT_MSG(0,"レイアウトID %d が不正です\n",id);
		id = 0;
	}
	sv->game_layout = id;
}

/**
 *	@brief	サファリゲーム中に参照するレイアウトIDの取得
 */
SAFARI_LAYOUT_ID SafariSv_GetGameLayoutID(SAFARI_SAVE* sv)
{
	return sv->game_layout;
}

/**
 *	@brief	サファリレイアウトデータポインタ　取得
 */
SAFARI_LAYOUT* SafariSv_GetLayoutPointer(SAFARI_SAVE* sv,SAFARI_LAYOUT_ID id)
{
	if(id == SAFARI_LAYOUT_GAME){
		id = sv->game_layout;
	}
	if(id >= SAFARI_LAYOUT_MAX){
		GF_ASSERT_MSG(0,"レイアウトID %d が不正です\n",id);
		id = 0;
	}
	return &sv->layout[id];
}

/**
 *	@brief	サファリレイアウトデータ　取得
 *
 *	＊構造体型のワークにコピー
 */
void SafariSv_GetLayout(SAFARI_SAVE* sv,SAFARI_LAYOUT_ID id,SAFARI_LAYOUT* pl)
{
	if(id >= SAFARI_LAYOUT_MAX){
		GF_ASSERT_MSG(0,"レイアウトID %d が不正です\n",id);
		layout_clear(pl);
		return;
	}
	MI_CpuCopy8(&sv->layout[id],pl,sizeof(SAFARI_LAYOUT));
}

/**
 *	@brief	サファリレイアウトデータセット
 *
 *	＊構造体型で受け取ってコピー
 */
void SafariSv_SetLayout(SAFARI_SAVE* sv,SAFARI_LAYOUT_ID id,const SAFARI_LAYOUT* pl)
{
	if(id >= SAFARI_LAYOUT_MAX){
		GF_ASSERT_MSG(0,"レイアウトID %d が不正です\n",id);
		return;
	}
	MI_CpuCopy8(pl,&sv->layout[id],sizeof(SAFARI_LAYOUT));
}

/**
 *	@brief	サファリレイアウト　レベルアップ遅延カウントを設定
 */
void SafariSv_SetLayoutLevelUpDelayCount(SAFARI_SAVE* sv,u8 delay_ct)
{
	if(delay_ct > 255){
		sv->lvup_delay_ct = 255;
	}else{
		sv->lvup_delay_ct = delay_ct;
	}
}

/**
 *	@brief	サファリレイアウト　レベルアップ遅延カウントを取得
 */
u8 SafariSv_GetLayoutLevelUpDelayCount(SAFARI_SAVE* sv)
{
	return sv->lvup_delay_ct;
}

/*
 *	@brief	サファリレイアウト　レベルアップ(日付更新処理で一日一回だけ呼び出す)
 *
 *	更新するのは自分のレイアウトだけ
 */
void SafariSv_LayoutLevelUp(SAFARI_SAVE* sv,s32 diff_days)
{
	int i,up_num;
	u8	up_buf[SAFARIL_BLOCK_MAX];
	SAFARI_LAYOUT* layout = &sv->layout[SAFARI_LAYOUT_MINE];

	if(diff_days <= 0){
		return;	//なにもしないで帰る
	}

	up_num = 0;
	MI_CpuClear8(up_buf,sizeof(u8)*SAFARIL_BLOCK_MAX);
	for(i = 0;i < SAFARIL_BLOCK_MAX;i++){
		u8 id = layout->block[i].map_id;

		//既にレベルアップさせたチップかどうか？
		if(mapchip_IsAlreadyLvUp(id,up_buf,up_num)){
			continue;
		}
		if(((int)layout->map_level[id]+diff_days) < 255){
			layout->map_level[id] += diff_days;
		}else{
			layout->map_level[id] = 255;
		}
		up_buf[up_num++] = id;
	}
}

/**
 *	@brief	サファリ　OBJレベルの取得
 */
u8 SafariSv_GetObjLevel(SAFARI_SAVE* sv)
{
	return sv->obj_level;
}

/*
 *	@brief	サファリ OBJレベルアップ
 */
u8 SafariSv_ObjLevelUp(SAFARI_SAVE* sv,u8 up_level)
{
	SafariSv_ObjLevelSet(sv,sv->obj_level+up_level);
	return sv->obj_level;
}

/**
 *	@brief	サファリ OBJレベルセット
 */
void SafariSv_ObjLevelSet(SAFARI_SAVE* sv,u8 level)
{
	if(level > SAFARI_OBJ_LEVEL_MAX){
		sv->obj_level = SAFARI_OBJ_LEVEL_MAX;
	}else{
		sv->obj_level = level;
	}
}

/*
 *	@brief	サファリ　イベントキータイム設定
 */
void SafariSv_SetEventKeyTime(SAFARI_SAVE* sv,const PLAYTIME* time)
{
	//分に直して保存(秒は無視)
	sv->evkey_time = time->hour*60+time->minute;
}

/**
 *	@brief サファリ　イベントキータイムチェック
 *	指定した時間分の差分があるかどうか？
 *
 *	@retval	0	達していない
 *	@retval	1	達した
 *	@retval	2	カンストにより達しない
 */
u8 SafariSv_CheckEventKeyTime(SAFARI_SAVE* sv,const PLAYTIME* time,u8 diff_hour)
{
	u16 now_time = time->hour*60+time->minute;
	if(now_time-sv->evkey_time >= diff_hour*60){
		return 1;
	}else if(now_time >= SAFARI_EVKEY_TIME_MAX){	//カンストのせいで達しない
		return 2;
	}
	return 0;	//未達
}

/**
 *	@brief	サファリ マネージャーデータ(通信相手データ)セット
 */
void SafariSv_SetFriendStatus(SAFARI_SAVE* sv,const MYSTATUS* pFriend, int heapID)
{
    SAFARI_MANAGER* dat = &sv->manager;

    dat->writerID = MyStatus_GetID(pFriend);
	dat->sex = MyStatus_GetMySex(pFriend);
	dat->region = MyStatus_GetRegionCode(pFriend);
	dat->version = MyStatus_GetRomCode(pFriend);
	{
		STRBUF* msgstr = STRBUF_Create( sizeof(dat->name), heapID);
		MyStatus_CopyNameString(pFriend, msgstr);
		STRBUF_GetStringCode(msgstr, dat->name, sizeof(dat->name));
		STRBUF_Delete(msgstr);
	}
    dat->valid = TRUE;
    dat->CheckTime = GF_RTC_GetDateTimeBySecond();  // データを貰った時刻
	dat->RTCOffset = OS_GetOwnerRtcOffset();        // 時間をずらした累積(比較用)
}

/**
 *	@brief	サファリ マネージャーデータ(通信相手データ)ゲット
 */
void SafariSv_GetFriendStatus(const SAFARI_SAVE* sv,MYSTATUS* pFriend)
{
    const SAFARI_MANAGER* dat = &sv->manager;

	MyStatus_SetID(pFriend , dat->writerID);
	MyStatus_SetMySex(pFriend, dat->sex);
	MyStatus_SetRegionCode(pFriend, dat->region);
	MyStatus_SetRomCode( pFriend, dat->version );
	MyStatus_SetMyName(pFriend, dat->name);
}

/**
 *	@brief	友だちサファリ　通信相手の性別を取得
 */
u8 SafariSave_GetFriendSex(const SAFARI_SAVE* sv)
{
    const SAFARI_MANAGER* dat = &sv->manager;
	return dat->sex;
}

/**
 *	@brief	サファリ マネージャーデータ(通信相手データ)があるのかどうか
 */
BOOL SafariSv_IsEnableData(const SAFARI_SAVE* sv)
{
    const SAFARI_MANAGER* dat = &sv->manager;
	return dat->valid;
}

/**
 *	@brief	サファリ マネージャーデータ(通信相手データ)を無効にするかどうか検査
 */
void SafariSv_CheckManagerData(SAFARI_SAVE* sv)
{
    SAFARI_MANAGER* dat = &sv->manager;

	if(dat->valid){
		s64 now = GF_RTC_GetDateTimeBySecond();
		if((now - dat->CheckTime) > SAFARI_DELETEDATA_HOUR){
			dat->valid = FALSE;
		}
		else if(dat->RTCOffset != OS_GetOwnerRtcOffset()){
			dat->valid = FALSE;
		}
	}
}

/////////////////////////////////////////////////////////////////
//レイアウト
/**
 *	@brief	サファリレイアウト　ブロックデータスワップ
 */
void SafariLayout_BlockSwap(SAFARI_LAYOUT* layout,u8 pos1,u8 pos2)
{
	SAFARI_BLOCK tmp;

	tmp = layout->block[pos1];
	layout->block[pos1] = layout->block[pos2];
	layout->block[pos2] = tmp;
}

/**
 *	@brief	サファリレイアウト　ブロックリプレース
 */
void SafariLayout_BlockReplace(SAFARI_LAYOUT* layout,SAFARI_BLOCK_ID block_id,SAFARI_MAP_ID map_id)
{
	block_clear(&layout->block[block_id],map_id);
}

/*
 *	@brief	サファリレイアウト　オブジェ配置追加
 */
void SafariLayout_AddObj(SAFARI_LAYOUT* layout,SAFARI_BLOCK_ID block_id,SAFARI_OBJ* obj)
{
	SAFARI_BLOCK*	bp;
	if(block_id >= SAFARI_BLOCK_MAX){
		GF_ASSERT(0);
		return;
	}
	bp = &layout->block[block_id];
	if(bp->obj_ct >= SAFARI_OBJ_MAX){
		GF_ASSERT_MSG(0,"オブジェ登録個数オーバー\n");
		return;
	}
	bp->obj[bp->obj_ct++] = *obj;
}

/*
 *	@brief	サファリレイアウト　オブジェ配置削除
 */
void SafariLayout_DelObj(SAFARI_LAYOUT* layout,SAFARI_BLOCK_ID block_id,u8 idx)
{
	int i;
	SAFARI_BLOCK*	bp;
	if(block_id >= SAFARI_BLOCK_MAX){
		GF_ASSERT(0);
		return;
	}
	bp = &layout->block[block_id];
	if(idx >= bp->obj_ct){
		GF_ASSERT_MSG(0,"削除しようとしているID %d:%d が無効です\n",block_id,idx);
		return;
	}
	bp->obj_ct--;
	if(idx == bp->obj_ct){
		obj_clear(&bp->obj[idx]);
		return;
	}
	//データを前に詰める
	for(i = idx;i < bp->obj_ct;i++){
		bp->obj[i] = bp->obj[i+1];
	}
	obj_clear(&bp->obj[bp->obj_ct]);
}

//////////////////////////////////////////////////////////////////////
///ローカル
/**
 *	@brief	サファリデータクリア
 */
static void safarisv_clear(SAFARI_SAVE* sv)
{
	MI_CpuClear8(sv,sizeof(SAFARI_SAVE));
}

/**
 *	@brief	サファリ　レイアウトクリア
 */
static void layout_clear(SAFARI_LAYOUT* layout)
{
	int i;

	for(i = 0;i < SAFARI_BLOCK_MAX;i++){
		block_clear(&layout->block[i],i);
	}
}

/**
 *	@brief	サファリブロックデータクリア
 */
static void block_clear(SAFARI_BLOCK* block,u8 block_id)
{
	MI_CpuClear8(block,sizeof(SAFARI_BLOCK));

	block->map_id = block_id;
}

/**
 *	@biref	オブジェデータクリア
 */
static void obj_clear(SAFARI_OBJ* obj)
{
	MI_CpuClear8(obj,sizeof(SAFARI_OBJ));
}

/*
 *	@brief	サファリ マネージャーデータ(通信相手データ)クリア
 */
static void manager_clear(SAFARI_MANAGER* dat)
{
	MI_CpuClear8(dat,sizeof(SAFARI_MANAGER));

	dat->writerID = 0;
	dat->sex = PM_MALE;
	dat->region = CasetteLanguage;
	dat->version = CasetteVersion;

	PM_strclearEOM_(dat->name,BUFLEN_PERSON_NAME);

}

/**
 *	@brief	既にレベルアップさせたチップかどうか判定
 */
static BOOL mapchip_IsAlreadyLvUp(u8 map_id,u8* up_list,u8 num)
{
	int i;

	for(i = 0;i < num;i++){
		if(map_id == up_list[i]){
			return TRUE;
		}
	}
	return FALSE;
}
